#include "../lib/pipc.hpp"
#include "../lib/localmap.hpp"
#include "../lib/servermap.hpp"

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <cstddef>
#include "tinyxml.h"

using namespace pipc;



Pipc* Pipc::_instance = NULL;

Pipc::Pipc()
{
    initialized_ = false;
    t_ = NULL;
}

Pipc* Pipc::Instance()
{
    if(_instance == NULL)
        _instance = new Pipc();
    return _instance;
}


bool Pipc::initialize(std::string fname, std::string id)
{
    id_ = id;
    TiXmlDocument doc(fname);
    if(!doc.LoadFile())
    {
        return false;
    }
    TiXmlNode *root = doc.RootElement();
    TiXmlNode *confRoot = root->FirstChild("pipc");

    if(confRoot == NULL)
    {
        return false;
    }

    TiXmlNode *transportRoot = confRoot->FirstChild("transport");
    if(transportRoot == NULL)
        return false;
    if(transportRoot->FirstChild("type") == NULL)
        return false;
    type_ = transportRoot->FirstChild("type")->FirstChild()->Value();
    if(type_ == "local")
    {
        return setupLocalTransport_();
    }
    if(type_ == "server")
    {
        return setupServerTransport_(transportRoot);
    }
    return false;
}

bool Pipc::release()
{
    if(!initialized_)
        return false;
    stop();
    if(type_ == "local")
        delete dynamic_cast<LocalMap*>(t_);
    if(type_ == "server")
        delete dynamic_cast<LocalMap*>(t_);
    initialized_ = false;
    return true;
}

bool Pipc::setupLocalTransport_()
{
    initialized_ = true;
    t_ = new LocalMap();
    return true;
}

bool Pipc::setupServerTransport_(TiXmlNode *transport)
{
    std::string ip;
    std::string port;
    std::string host;

    if(transport->FirstChild("host") == NULL)
        return false;
    host = transport->FirstChild("host")->FirstChild()->Value();
    std::vector <std::string> args;
    boost::split(args,host,boost::is_any_of(":"));
    ip = args[0];
    port = args[1];
    t_ = new ServerMap(ip, boost::lexical_cast<int>(port), id_);
    initialized_ = true;
    return true;
}

void Pipc::setValue(std::string key, Record value)
{
    if(initialized_)
        t_->setValue(key,value);
}

bool Pipc::isSynced(std::string key)
{
    if(initialized_)
        return t_->isSynced(key);
    return false;

}

Record Pipc::getValue(std::string key)
{
    if(initialized_)
        return t_->getValue(key);
    Record r;
    r.data = "";
    gettimeofday(&r.effective,NULL);
    return r;
}

void Pipc::clear()
{
    if(initialized_)
        t_->clear();
}

bool Pipc::subscribe(std::string key, bool reader)
{
    if(initialized_)
        return t_->subscibe(key, reader);
    return false;
}

bool Pipc::start()
{
    if(initialized_)
    {
        t_->start();
        boost::this_thread::sleep(boost::posix_time::milliseconds(100));
        return t_->isRunning();
    }
    return false;
}

bool Pipc::stop()
{
    if(initialized_)
    {
        t_->stop();
        boost::this_thread::sleep(boost::posix_time::milliseconds(100));
    }
    return !t_->isRunning();
}

bool Pipc::isRunning()
{
    if(initialized_)
    {
        return t_->isRunning();
    }
    return false;
}

